import React from 'react';

// 实现简单观察者模式，监听数据的set
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const observable = obj =>
  new Proxy(obj, {
    get: (target, key) => {
      console.log('get', target, key);
      // return new Date().getTime()
    },
    set: (target, key, value, receiver) => {
      const result = Reflect.set(target, key, value, receiver);
      console.log('result 数据', result, 't', target, 'k', key, 'v', value, 'r', receiver);
      // 执行副作用
      queuedObservers.forEach(observer => observer());
      return result;
    }
  });

console.log('queuedObservers 初始', queuedObservers);
// 使用观察者模式函数包裹
const person = observable({ name: 'tlx', time: '2023-03-05' });
observe(() => {
  console.log('观察者模式 每次改变数据时打印', person);
});
setTimeout(() => {
  person.name = '77778';
  // console.log( person.time )
}, 3000);

// 实现发布订阅模式
// 发布者
const psEvent = {
  clientList: {},
  listen: function (key, fn) {
    if (!this.clientList[key]) this.clientList[key] = [];
    this.clientList[key].push(fn); // 订阅的消息添加进对应类型的缓存列表
  },
  trigger: function () {
    // 删除并拿到arguments的第一项
    // [].shift.call(arguments) === Array.prototype.shift.call(arguments)
    const key = [].shift.call(arguments);
    const fns = this.clientList[key];
    if (!fns || fns.length === 0) {
      // 如果没有板顶对应的消息
      return false;
    }
    for (let i = 0; i < fns.length; i++) {
      fns[i].apply(this, arguments); // arguments 是 trigger 时传入的参
    }
  },
  remove: function (key, fn) {
    let fns = this.clientList[key];
    if (!fns || fns.length === 0) return false;
    if (!fn) {
      fns.length = 0;
    } else {
      for (let i = 0; i < fns.length; i++) {
        const _fn = fns[i];
        if (_fn === fn) {
          fns.splice(i, 1);
        }
      }
    }
  }
};
// 给所有对象都动态安装发布-订阅功能
const installEvent = function (obj) {
  // const EventObj = obj ? obj : Object.create(null);
  for (var i in psEvent) {
    obj[i] = psEvent[i];
  }
};
// 使用
const salesOffices = {};
installEvent(salesOffices); //给 salesOffices 对象安装发布订阅功能
console.log('salesOffices', salesOffices);
const sm88 = p => {
  console.log('发布-订阅功能 sm88', p);
};
// 测试
salesOffices.listen('sm88', sm88);
salesOffices.listen('sm110', p => {
  console.log('发布-订阅功能 sm110', p);
});

// 移除订阅
salesOffices.remove('sm88', sm88);
// 发布消息
salesOffices.trigger('sm88', 20, 20000);
salesOffices.trigger('sm110', 11, 110000);

export default function Algorithm() {
  return <div>Algorithm: 订阅-订阅模式，观察者模式 https://blog.csdn.net/MFWSCQ/article/details/106314013</div>;
}
